﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Management;
using System.Net.NetworkInformation;
using System.Text;
using NLog;

namespace DeSleeper.Library
{
	internal class NetworkInterfaceHelper
	{
		private static readonly Logger _logger = LogManager.GetCurrentClassLogger();

		internal static bool AreInterfacesEqual(NetworkInterface baseInterface, ManagementBaseObject adapter)
		{
			// Only 2003/Vista and higher support GUID
			if (OSHelper.Is2003VistaOrGreater 
				&& String.Equals(baseInterface.Id, TryGetString(adapter, "GUID"), StringComparison.OrdinalIgnoreCase))
				return true;

			if (!String.Equals(baseInterface.Name, TryGetString(adapter, "NetConnectionID"), StringComparison.OrdinalIgnoreCase))
				return false;

			if (!String.Equals(baseInterface.GetPhysicalAddress().ToString(), TryGetString(adapter, "MACAddress").Replace(":", String.Empty), StringComparison.OrdinalIgnoreCase))
			{
				_logger.Warn("MACAddress mismatch {0}, {1}", baseInterface.GetPhysicalAddress().ToString(), TryGetString(adapter, "MACAddress"));
				return false;
			}

			return true;
		}

		internal static NetworkInterface[] TryGetNetworkInterfaces()
		{
			try
			{
				return NetworkInterface.GetAllNetworkInterfaces();
			}
			catch (NetworkInformationException e)
			{
				_logger.FatalException("Failed to get network interface information.", e);
				return null;
			}
		}

		internal static List<ManagementBaseObject> TryGetAdapters()
		{
			try
			{
				List<ManagementBaseObject> adapters;
				using (var adapterSearch = new ManagementObjectSearcher(new ManagementScope("root/Cimv2"), new ObjectQuery("SELECT * FROM Win32_NetworkAdapter WHERE AdapterTypeId=0")))
				using (var adapterCollection = adapterSearch.Get())
				{
					adapters = adapterCollection.OfType<ManagementBaseObject>().ToList();
				}
				return adapters;
			}
			catch (Exception e)
			{
				_logger.FatalException("Failed to get network interface information.", e);
				return null;
			}
		}

		internal static string TryGetString(ManagementBaseObject obj, string propertyName)
		{
			try
			{
				return obj[propertyName] as string;
			}
			catch (ManagementException e)
			{
				_logger.WarnException(String.Format(CultureInfo.CurrentUICulture, 
				                                    "Failed to get network property {0}.", propertyName),
				                      e);
				return String.Empty;
			}
		}
	}
}
